package cn.edu.seu.ssny.service.impl;

import cn.edu.seu.ssny.common.Constants;
import cn.edu.seu.ssny.entity.Project;
import cn.edu.seu.ssny.enums.ResultCodeEnum;
import cn.edu.seu.ssny.exception.SsnyException;
import cn.edu.seu.ssny.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 数据分析服务
 */
@Service
public class StatisticsServiceImpl implements IStatisticsService {

    @Autowired
    private IQueryDeviceService queryDeviceService;
    @Autowired
    private IQueryDataService queryDataService;

    /**
     * 功能描述:
     * <根据项目ID计算出该项目设备类别的能耗(指定项目)
     * <example:
     * <返回
     * <类别1-能耗量
     * <...
     * <类别N-能耗量
     *
     * @param project
     * @return
     */
    @Override
    public Map<String, Double> caculatePowercostByProject(Project project) {
        //占比类型-占比类型对应的采集点ID集合
        Map<String, List<Integer>> rateType = queryDeviceService.findAllPowercostRateTypeAndDeviceIds(project);
        Map<String, Double> result = new HashMap<>();
        for (Map.Entry<String, List<Integer>> item : rateType.entrySet()) {
            String itemName = item.getKey();
            List<Integer> deviceIds = item.getValue();
            Double powercost = queryDataService.getSumOfRecentOneDataOfDevices(deviceIds);
            result.put(itemName, powercost);
        }
        return result;
    }


    /**
     * 功能描述:
     * <根据时间列表计算出机组能效
     * <example
     * <dates [20210707,20210708,20210709,20210710]
     * <timeMode = MODE_DAY
     * <返回
     * <机组1--[20210707能效，20210708能效...]
     * <...
     * <机组N--[20210707能效，20210708能效...]
     *
     * @param project
     * @param dates
     * @param timeMode
     * @return
     */
    @Override
    public Map<String, List<Double>> caculateMachineGroupEfficiencyByProject(Project project, List<Date> dates, int timeMode) {
        Map<String, List<Integer>> machineGroupsPowercost = queryDeviceService.findAllMachineGroupAndPowercostDeviceIds(project);
        Map<String, List<Integer>> machineGroupsEnergy = queryDeviceService.findAllMachineGroupAndEnergyDeviceIds(project);
        int length = dates.size();
        Map<String, List<Double>> result = new HashMap<>();
        dates.add(new Date());
        for (Map.Entry<String, List<Integer>> item : machineGroupsPowercost.entrySet()) {
            String machineGroupName = item.getKey();
            List<Integer> powercostDeviceIds = item.getValue();
            List<Double> thePowercosts = queryDataService.getPeroidSumofDevicesByDateList(powercostDeviceIds, dates, timeMode);
            List<Integer> energyDeviceIds = machineGroupsEnergy.get(machineGroupName);
            List<Double> theEnergy = queryDataService.getPeroidSumofDevicesByDateList(energyDeviceIds, dates, timeMode);
            if (thePowercosts.size() < dates.size() - 1 || theEnergy.size() < dates.size() - 1) {
                throw new SsnyException(ResultCodeEnum.ERROR_DATA_LOST);
            }
            if (thePowercosts.size() > dates.size() - 1 || theEnergy.size() > dates.size() - 1) {
                throw new SsnyException(ResultCodeEnum.ERROR_DATA_REDUNDANT);
            }
            List<Double> theMachineGroupEfficiency = new ArrayList<>(length);
            for (int i = 0; i < length; i++) {
                if (thePowercosts.get(i) == 0) {
                    theMachineGroupEfficiency.add(0d);
                } else {
                    theMachineGroupEfficiency.add(theEnergy.get(i) / thePowercosts.get(i));
                }
            }
            result.put(machineGroupName, theMachineGroupEfficiency);
        }
        dates.remove(dates.size() - 1);
        return result;
    }

    /**
     * 功能描述:
     * <example
     * <dates [20210707,20210708,20210709,20210710]
     * <timeMode = MODE_DAY
     * <mode = 制冷
     * <返回
     * <[20210707制冷能效，20210708制冷能效...,20210710制冷能效]
     *
     * @param project
     * @param dates
     * @param mode     制冷模式 或者 供暖模式
     * @param timeMode
     * @return
     */
    @Override
    public List<Double> caculateSystemEfficiency(Project project, List<Date> dates, int mode, int timeMode) {
        List<Integer> powercostDeviceIds = null; //能耗采集点
        List<Integer> energyDeviceIds = null; //制冷或者供暖量采集点
        if (mode == Constants.CoolingMode) {
            powercostDeviceIds = queryDeviceService.findAllCoolingPowercostDeviceIds(project);
            energyDeviceIds = queryDeviceService.findAllCoolingEnergyDeviceIds(project);
        } else if (mode == Constants.HeatingMode) {
            powercostDeviceIds = queryDeviceService.findAllHeatingPowercostDeviceIds(project);
            energyDeviceIds = queryDeviceService.findAllHeatingEnergyDeviceIds(project);
        } else {
            //模式选择错误，抛出异常
            throw new SsnyException(ResultCodeEnum.ERROR_MODE);
        }
        dates.add(new Date());
        List<Double> powercosts = queryDataService.getPeroidSumofDevicesByDateList(powercostDeviceIds, dates, timeMode);
        List<Double> energies = queryDataService.getPeroidSumofDevicesByDateList(energyDeviceIds, dates, timeMode);
        dates.remove(dates.size() - 1);
        if (powercosts.size() < dates.size() || energies.size() < dates.size()) {
            throw new SsnyException(ResultCodeEnum.ERROR_DATA_LOST);
        }
        if (powercosts.size() > dates.size() || energies.size() > dates.size()) {
            throw new SsnyException(ResultCodeEnum.ERROR_DATA_REDUNDANT);
        }
        List<Double> result = new ArrayList<>();
        for (int i = 0; i < dates.size(); i++) {
            if (energies.get(i) == 0) {
                result.add(0d);
            } else {
                result.add(powercosts.get(i) / energies.get(i));
            }
        }
        return result;
    }

    /**
     * 功能描述:
     * <计算可再生能源利用量
     *
     * @return
     */
    @Override
    public Double caculateRenewEnergy() {
        List<Integer> deviceIds = queryDeviceService.findAllRenewEnergyDeviceIds();
        return queryDataService.getSumOfRecentOneDataOfDevices(deviceIds);
    }

    /**
     * 功能描述:
     * <计算节约标煤量
     *
     * @return
     */
    @Override
    public Double caculateCoalSaved() {
        List<Integer> deviceIds = queryDeviceService.findAllCoalSavedDeviceIds();
        return queryDataService.getSumOfRecentOneDataOfDevices(deviceIds);
    }

    /**
     * 功能描述:
     * <计算碳排放量
     *
     * @return
     */
    @Override
    public Double caculateCarbonEmission() {
        List<Integer> deviceIds = queryDeviceService.findAllCarbonEmissionDeviceIds();
        return queryDataService.getSumOfRecentOneDataOfDevices(deviceIds);
    }

    /**
     * 功能描述:
     * <计算系统能耗指标
     *
     * @param project
     * @param dates
     * @param timeMode
     * @param mode     供暖模式 或者 制冷模式
     * @return
     */
    @Override
    public List<Double> caculateSystemPowercostStd(Project project, List<Date> dates, int timeMode, int mode) {
        List<Integer> deviceIds = null;
        if (mode == Constants.HeatingMode) {
            deviceIds = queryDeviceService.findAllSystemPowercostStdOnHeatingModeDevices(project);
        } else if (mode == Constants.CoolingMode) {
            deviceIds = queryDeviceService.findAllSystemPowercostStdOnCoolingModeDevices(project);
        } else {
            throw new SsnyException(ResultCodeEnum.ERROR_MODE);
        }
        dates.add(new Date());
        List<Double> powercosts = queryDataService.getPeroidSumofDevicesByDateList(deviceIds, dates, timeMode);
        List<Double> results = new ArrayList<>();
        dates.remove(dates.size() - 1);
        if (powercosts.size() < dates.size()) {
            throw new SsnyException(ResultCodeEnum.ERROR_DATA_LOST);
        }
        if (powercosts.size() > dates.size()) {
            throw new SsnyException(ResultCodeEnum.ERROR_DATA_REDUNDANT);
        }
        double area = project.getArea() * 10000; //万平方米->平方米
        for (int i = 0; i < dates.size(); i++) {
            if (area == 0) {
                results.add(0d);
            } else {
                results.add(powercosts.get(i) / area);
            }
        }
        return results;
    }
}
